using System;
using Gtk;
namespace MonoBED3
{
	[System.ComponentModel.ToolboxItem(true)]
	public class XZView : Gtk.DrawingArea, ContextAware, ContextListener, Zoomable
	{
//-----------------------------------------------------------------------------		
	//	private EditorContext getContext();
		bool shouldDrawGrid = false;
		private Vector3 myCursorRef;
		private Vector3 dragBeginPoint;
		private int panX;
		private int panY;
		private ZoomLevelListener listener;
		private byte zoom; // 1 - mais afastado, 255 - mais próximo.
		bool shouldDrawAsSolids = true;
//-----------------------------------------------------------------------------		
		public void setContext(EditorContext instance)
		{
		//	getContext() = instance;	
			myCursorRef = getContext().getCursor();			
		}
		
		public void setDrawAsSolids( bool shouldDrawAsSolids ) {
			this.shouldDrawAsSolids = shouldDrawAsSolids;
		}
		
//-----------------------------------------------------------------------------		
		public EditorContext getContext()
		{
			return MainWindow.editContext;	
		}
		
		public void contextModified() {
		}
		
		public void setZoomLevel( byte zoom ) {
			this.zoom = zoom;
			QueueDraw();
		}
		
		public XZView ( ZoomLevelListener listener )
		{
			this.listener = listener;
			zoom = 10;
			listener.zoomLevelChanged( 10 );
			AddEvents((int)Gdk.EventMask.AllEventsMask);
		}
		
		private int getScreenX( int mapX ) {
			return panX + ( mapX ) * zoom;
		}
		
		private int getScreenY( int mapY ) {
			return panY + ( mapY ) * zoom;
		}		
		
		private int getScreenX( float mapX ) {
			return getScreenX( ( int )mapX );
		}
		
		private int getScreenY( float mapY ) {
			return getScreenY( ( int )mapY );
		}				
		
		private float convertToUniversalX( float x)
		{
			return ( x - panX  ) / zoom;
		}

		private float convertToUniversalY( float y)
		{
			return y;
		}

		private float convertToUniversalZ( float z)
		{
			return ( z - panY ) / zoom;
		}
		
		protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
		{
			
			if ( dragBeginPoint != null ) {
				panX += ( int ) ( evnt.X - dragBeginPoint.getX() );
				panY += ( int ) ( evnt.Y - dragBeginPoint.getZ() );
				dragBeginPoint.setVec( ( float )evnt.X, 0.0f, ( float )evnt.Y );				
				QueueDraw();
			}
			
			
			return true;
		}
	

		protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
		{
			dragBeginPoint = null;
			
			return true;		}
		
		
		
		
		protected override bool OnScrollEvent (Gdk.EventScroll evnt)
		{
			if ( evnt.Direction == Gdk.ScrollDirection.Up ) {
				++zoom;
			} else {
				--zoom;
			}
			
			if ( zoom <= 0 )
				zoom = 1;
			
			if ( zoom >= 254 )
				zoom = 254;
				
				//Console.WriteLine( "scroll:" + zoom );
			
			this.QueueDraw();
			
			listener.zoomLevelChanged( zoom );
			
			return true;//base.OnScrollEvent (evnt);
		}

		
		
		protected override bool OnButtonPressEvent (Gdk.EventButton ev)
		{
			switch (ev.Button)
			{
			case 1:		
				
				if ( dragBeginPoint != null )
					return true ;
				
			//	System.Console.WriteLine("movendo cursor");
				myCursorRef.setX( convertToUniversalX( ( float ) ev.X ) );
			//	myCursorRef.setY( float.PositiveInfinity );
				myCursorRef.setZ( convertToUniversalZ( ( float ) ev.Y)  );
				dragBeginPoint = new Vector3( ( float ) ev.X, 0.0f, ( float )ev.Y );				
				getContext().setCurrentEntityFromCursor();		
				break;
			case 2:
				
				{
				System.Console.WriteLine("movendo entidade");
				GameObjectFacade proxy = getContext().getCurrentEntityFacade();
				GameObject obj = (GameObject)proxy.getObject();
				myCursorRef.setX( convertToUniversalX( ( float ) ev.X));
			//	myCursorRef.setY( float.PositiveInfinity );				
				myCursorRef.setZ( convertToUniversalZ( ( float ) ev.Y));		
				
				if ( MainWindow.altButtonBehaviour != 0 )
					obj.moveTo( myCursorRef.getX(), myCursorRef.getY() , myCursorRef.getZ() );
				else {
					if (obj is Sector) {
						((Sector)obj).setDX(myCursorRef.getX() - obj.getX());
						((Sector)obj).setDZ(myCursorRef.getZ() - obj.getZ());					
					}
				}
					
				}

				break;
			case 3:		
				{
				System.Console.WriteLine("redimensionando entidade");
				GameObjectFacade proxy = getContext().getCurrentEntityFacade();
				GameObject obj = (GameObject)proxy.getObject();
				myCursorRef.setX( convertToUniversalX( ( float ) ev.X) );
			//	myCursorRef.setY( float.PositiveInfinity );
				myCursorRef.setZ( convertToUniversalZ( ( float ) ev.Y) );
				
				if ( MainWindow.altButtonBehaviour != 0 ) {
					if (obj is Sector) {
						((Sector)obj).setDX(myCursorRef.getX() - obj.getX());
						((Sector)obj).setDZ(myCursorRef.getZ() - obj.getZ());					
					}

				} else {
					obj.moveTo( myCursorRef.getX(), myCursorRef.getY() , myCursorRef.getZ() );
				}
			}
			break;				
			default:
				System.Console.WriteLine("sei la");
				break;
			}
			
			getContext().askForScreenRefresh();			
			return base.OnButtonPressEvent (ev);
		}
		
		private void drawWorldLimits()
		{		
			StateType state;
			Gdk.GC gc;

			state = StateType.Active;
			gc = Style.BaseGC(state);
		
			gc.RgbFgColor = new Gdk.Color( 0, 0, 0 );
			
			GdkWindow.DrawLine(gc, getScreenX( 0 ), getScreenY( 0 ), getScreenX( 255 ), getScreenY( 0 ) );
			GdkWindow.DrawLine(gc, getScreenX( 0 ), getScreenY( 0 ), getScreenX( 0 ), getScreenY( 255 ) );
			GdkWindow.DrawLine(gc, getScreenX( 0 ), getScreenY( 255 ), getScreenX( 255 ), getScreenY( 255 ) );
			GdkWindow.DrawLine(gc, getScreenX( 255 ), getScreenY( 0 ), getScreenX( 255 ), getScreenY( 255 ) );
			
		}
		
		private void drawGrid()
		{		
			int sizeX, sizeZ, strideX, strideZ;
			StateType state;
			Gdk.GC gc;

			state = StateType.Active;
			gc = Style.BaseGC(state);
			
			sizeX = 512;
			sizeZ = 512;
			strideX = zoom + 1;
			strideZ = zoom + 1;
			
			byte color = ( byte )( 255 - zoom );
			gc.RgbFgColor = new Gdk.Color( color, color, color );
			
			for (int x=0; x < sizeX * strideX; x+= strideX )		
				GdkWindow.DrawLine(gc, panX + x, 0, panX + x,sizeZ);				
			
			
			for (int z=0; z < sizeZ * strideZ; z+= strideZ )		
				GdkWindow.DrawLine(gc,0, panY + z,sizeX, panY + z);		
		
		}
		
		private void drawSector( SectorFacade sf, Gdk.GC gc ) {

				gc.RgbFgColor = sf.getGtkColor( 5 );
				
				int x0 = getScreenX( sf.getX() );
				int x1 = getScreenX( sf.getX() + sf.getDX() );
				int z0 = getScreenY( sf.getZ() );
				int z1 = getScreenY( sf.getZ() + sf.getDZ() );
				
				if ( shouldDrawAsSolids ) {
					GdkWindow.DrawRectangle(gc, true, x0, z0, x1 - x0, z1 - z0 );				
				}
				
				for ( int c = 0; c < 6; ++c ) {
				
					if ( ( ( Sector )sf.getObject() ).IsDoorAt( c ) ) 
						gc.RgbFgColor = new Gdk.Color( 255, 0, 0 );
					else if ( getContext().getCurrentSectorId() == sf.getId() )
						gc.RgbFgColor = new Gdk.Color( 0, 0, 255 );
					else if ( ( ( Sector ) sf.getObject() ).getLink( c ) == 0 )
						gc.RgbFgColor = new Gdk.Color( 0, 0, 0 );
					else
						continue;
						
						switch( c ) {
							case 0:
								GdkWindow.DrawLine( gc, x0, z0, x1, z0 );
								break;
							case 1:
								GdkWindow.DrawLine( gc, x1, z0, x1, z1 );
								break;
							case 2:
								GdkWindow.DrawLine( gc, x0, z1, x1, z1 );
								break;							
							case 3:
								GdkWindow.DrawLine( gc, x0, z0, x0, z1 );
								break;
							case 4:
								GdkWindow.DrawLine( gc, x0, z0, x1, z1 );
								break;
							case 5:
								GdkWindow.DrawLine( gc, x1, z0, x0, z1 );
								break;							
						}
					
				}
		}
				
		protected override bool OnExposeEvent (Gdk.EventExpose ev)
		{
			//base.OnExposeEvent (ev);
			
			//if ( getContext().isLocked() ) {
			//	QueueDraw();//?
			//	return true;
			//}
			
			StateType state;
			Gdk.GC gc;
			GameObjectFacade go = null;
			int current;			
			int width;
			int height;
			ev.Window.GetSize( out width, out height );
			state = StateType.Normal;
			gc = Style.BaseGC(state);
		//	gc.RgbFgColor = new Gdk.Color(0,0,255);
			GdkWindow.DrawRectangle(gc,true,0,0,512,255);
			drawWorldLimits();
			
			if ( shouldDrawGrid ) {
				drawGrid();
			}
			
			state = StateType.Selected;
			gc = Style.BaseGC(state);

			
			current = 1;
			SectorFacade sf;
			
			sf = getContext().getSectorFacade(current);
			
			while (sf != null)
			{			
				drawSector( sf, gc );
				current++;
				sf = getContext().getSectorFacade(current);
			}	
			
			if (  getContext().getCurrentSectorId() != 0 ) {
				
				sf = getContext().getSectorFacade( getContext().getCurrentSectorId() );
				drawSector( sf, gc );				
			}
			
			gc.RgbFgColor = new Gdk.Color( 0, 255, 0 );
			
			current = 0;
			go = getContext().getActorFacade(current);
			
			while (go != null)
			{
				Console.WriteLine("Ator...");
				GdkWindow.DrawRectangle(gc, true, ( int ) go.getX(), ( int ) go.getZ(),5,5);
				current++;
				go = getContext().getActorFacade(current);
			}	

			if (myCursorRef == null)
				return true; 
			
			gc.RgbFgColor = new Gdk.Color( 0,0,255);
			GdkWindow.DrawLine( gc, 0, getScreenY( myCursorRef.getZ() ) + 2, width, getScreenY( myCursorRef.getZ() ) + 2);
			GdkWindow.DrawLine( gc, getScreenX( myCursorRef.getX() ) + 2, 0, getScreenX( myCursorRef.getX() ) + 2, height );
			GdkWindow.DrawRectangle(gc, true, getScreenX( myCursorRef.getX() ), getScreenY( myCursorRef.getZ() ),5,5);
			
			return true;
		}
		
		
		protected override void OnSizeRequested (ref Gtk.Requisition requisition)
		{
			requisition.Height = 255;
			requisition.Width = 512;
		}

		public void reset() {
			this.zoom = 10;
			this.panX = 0;
			this.panY = 0;
			this.QueueDraw();
		}
		
		public void setDrawGrid( bool shouldDrawGrid ) {
			this.shouldDrawGrid = shouldDrawGrid;
		}		
	}
}

